package concurrent.lock;

import org.junit.Test;

import java.util.concurrent.locks.StampedLock;

/**
 * 票据锁
 * StampedLock和ReentrantReadWriteLock类似，只是StampedLock的可以使用乐观读
 * @author tuyou
 * @date 2020-08-17 22:44:59
 */
public class StampedLockTest {

    @Test
    public void writeLockTest() {
        StampedLock lock = new StampedLock();
        long stamp = lock.writeLock();
        lock.unlockWrite(stamp);
    }

    @Test(expected = IllegalMonitorStateException.class)
    public void lockExceptionTest() {
        StampedLock lock = new StampedLock();
        lock.writeLock();
        lock.unlockWrite(11);
    }

    @Test
    public void writeReadLockTest() {
        StampedLock lock = new StampedLock();
        long stamp = lock.writeLock();
        long stamp2 = lock.tryReadLock();
        System.out.println(stamp);
        System.out.println(stamp2);

        assert stamp != 0;
        assert stamp2 == 0;
    }

    @Test
    public void doubleWriteLockTest() {
        StampedLock lock = new StampedLock();
        long stamp = lock.writeLock();
        long stamp2 = lock.tryWriteLock();
        System.out.println(stamp);
        System.out.println(stamp2);

        assert stamp != 0;
        assert stamp2 == 0;
    }

    @Test
    public void doubleReadLockTest() {
        StampedLock lock = new StampedLock();
        long stamp = lock.readLock();
        long stamp2 = lock.tryReadLock();
        System.out.println(stamp);
        System.out.println(stamp2);

        assert stamp != 0;
        assert stamp2 != 0;
    }

    /**
     * 乐观读测试
     * @author tuyou
     * @date 2020-08-17 22:53:09
     */
    @Test
    public void optimisticReadTest() {
        StampedLock lock = new StampedLock();
//        long writeStamp = lock.writeLock();
        long stamp = lock.tryOptimisticRead();
        System.out.println(stamp);
        if (lock.validate(stamp)) {
            long stamp2 = lock.readLock();
            try {
//                System.out.println(stamp2);
//
//                long l = lock.writeLock();
//                System.out.println(l);
            } finally {
                lock.unlockRead(stamp2);
            }
        }
    }

    class Point {
        private double x, y;
        private final StampedLock sl = new StampedLock();

        void move(double deltaX, double deltaY) { // an exclusively locked method
            long stamp = sl.writeLock();
            try {
                x += deltaX;
                y += deltaY;
            } finally {
                sl.unlockWrite(stamp);
            }
        }

        double distanceFromOrigin() { // A read-only method
            long stamp = sl.tryOptimisticRead();
            double currentX = x, currentY = y;
            if (!sl.validate(stamp)) {
                stamp = sl.readLock();
                try {
                    currentX = x;
                    currentY = y;
                } finally {
                    sl.unlockRead(stamp);
                }
            }
            return Math.sqrt(currentX * currentX + currentY * currentY);
        }

        void moveIfAtOrigin(double newX, double newY) { // upgrade
            // Could instead start with optimistic, not read mode
            long stamp = sl.readLock();
            try {
                while (x == 0.0 && y == 0.0) {
                    long ws = sl.tryConvertToWriteLock(stamp);
                    if (ws != 0L) {
                        stamp = ws;
                        x = newX;
                        y = newY;
                        break;
                    }
                    else {
                        sl.unlockRead(stamp);
                        stamp = sl.writeLock();
                    }
                }
            } finally {
                sl.unlock(stamp);
            }
        }
    }
}
